﻿using Blm.Utils.Utility;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.DrawingCore;
using System.IO;
using System.Threading.Tasks;
using VisionCloud.Core.Model.Ms;

namespace VisionCloud.Domain.DtoModel.Ms
{
    /// <summary>
    /// RoomMap
    /// </summary>
    public class RoomMap
    {
        public List<LayoutPartStruct> Parts { get; private set; }

        //public List<Point> MeasurePoints { get; set; }
        public double Height { get; private set; }

        public double Width { get; private set; }
        public double deviationX { get; private set; }
        public double deviationY { get; private set; }

        public RoomMap()
        {
            Height = 0;
            Width = 0;
            deviationX = 0;
            deviationY = 0;
            Parts = new List<LayoutPartStruct>();
            //MeasurePoints = new List<Point>();
        }

        public void LoadFromJson(string json)
        {
            Parts.Clear();
            //MeasurePoints.Clear();
            Height = 0;
            Width = 0;
            deviationX = 0;
            deviationY = 0;
            double maxX = 0, minX = 0, maxY = 0, minY = 0;
            var jarray = JArray.Parse(json);
            foreach (var item in jarray)
            {
                var jpart = JObject.Parse(item.ToString());
                LayoutPartStruct part = new LayoutPartStruct();
                part.ID = jpart["id"].ToString();
                string type = jpart["type"].ToString();
                part.TypeName = type;
                switch (type)
                {
                    case "beam": part.TypeID = 0; break;
                    case "floor": part.TypeID = 1; break;
                    case "wall": part.TypeID = 2; break;
                    case "door": part.TypeID = 4; break;
                    case "column": part.TypeID = 3; break;
                    case "window": part.TypeID = 5; break;
                    case "partitionwall": part.TypeID = 6; break;
                    case "room": part.TypeID = 7; break;
                }
                var jshapes = JArray.Parse(jpart["shapes"].ToString());
                foreach (var shape in jshapes)
                {
                    var jshape = JObject.Parse(shape.ToString());
                    var jpoints = JArray.Parse(jshape["points"].ToString());
                    PointSet pointSet = new PointSet(jpoints.Count);
                    for (int i = 0; i < jpoints.Count; i++)
                    {
                        double x = Math.Round(Convert.ToDouble(jpoints[i]["x"]), 2);
                        double y = Math.Round(Convert.ToDouble(jpoints[i]["y"]), 2);
                        pointSet.Points[i].X = (int)x;
                        pointSet.Points[i].Y = (int)y;
                        if (maxX < x) maxX = x;
                        if (maxY < y) maxY = y;
                        if (minX > x) minX = x;
                        if (minY > y) minY = y;
                    }
                    part.Shapes.Add(pointSet);
                }
                if (part.Shapes.Count > 0) Parts.Add(part);
            }
            deviationX = (minX - 1000) * -1;
            deviationY = (minY - 1000) * -1;
            Width = (maxX - minX) + 2000;
            Height = (maxY - minY) + 2000;
            Parts.Sort((x, y) => x.TypeID.CompareTo(y.TypeID));
        }

        public void LoadFromFile(string filename)
        {
            Parts.Clear();
            //MeasurePoints.Clear();
            Height = 0;
            Width = 0;
            deviationX = 0;
            deviationY = 0;
            double maxX = 0, minX = 0, maxY = 0, minY = 0;
            using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
            {
                using (StreamReader reader = new StreamReader(fs))
                {
                    string json = reader.ReadToEnd();
                    var jjj = JObject.Parse(json);
                    var jj = JObject.Parse(jjj["bim_sub_models"].ToString());
                    var jarray = JArray.Parse(jj["floor_plan"].ToString());
                    foreach (var item in jarray)
                    {
                        var jpart = JObject.Parse(item.ToString());
                        LayoutPartStruct part = new LayoutPartStruct();
                        part.ID = jpart["id"].ToString();
                        string type = jpart["type"].ToString();
                        part.TypeName = type;
                        switch (type)
                        {
                            case "beam": part.TypeID = 0; break;
                            case "floor": part.TypeID = 1; break;
                            case "wall": part.TypeID = 2; break;
                            case "door": part.TypeID = 4; break;
                            case "column": part.TypeID = 3; break;
                            case "window": part.TypeID = 5; break;
                            case "partitionwall": part.TypeID = 6; break;
                            case "room": part.TypeID = 7; break;
                        }
                        var jshapes = JArray.Parse(jpart["shapes"].ToString());
                        foreach (var shape in jshapes)
                        {
                            var jshape = JObject.Parse(shape.ToString());
                            var jpoints = JArray.Parse(jshape["points"].ToString());
                            PointSet pointSet = new PointSet(jpoints.Count);
                            for (int i = 0; i < jpoints.Count; i++)
                            {
                                double x = Math.Round(Convert.ToDouble(jpoints[i]["x"]), 2);
                                double y = Math.Round(Convert.ToDouble(jpoints[i]["y"]), 2);
                                pointSet.Points[i].X = (int)x;
                                pointSet.Points[i].Y = (int)y;
                                if (maxX < x) maxX = x;
                                if (maxY < y) maxY = y;
                                if (minX > x) minX = x;
                                if (minY > y) minY = y;
                            }
                            part.Shapes.Add(pointSet);
                        }
                        if (part.Shapes.Count > 0) Parts.Add(part);
                    }
                    deviationX = (minX - 1000) * -1;
                    deviationY = (minY - 1000) * -1;
                    Width = (maxX - minX) + 2000;
                    Height = (maxY - minY) + 2000;
                }
            }
            Parts.Sort((x, y) => x.TypeID.CompareTo(y.TypeID));
        }

        public async Task<string> GetImage()
        {
            return await Task.Run(() =>
             {
                 //保存文件至指定位置
                 Bitmap bit = new Bitmap(800, 800);
                 Graphics g = Graphics.FromImage(bit);
                 g.Clear(Color.White);
                 double rate_height = 800 / Height;
                 double rate_width = 800 / Width;
                 double rate = rate_height > rate_width ? rate_width : rate_height;
                 foreach (var part in Parts)
                 {
                     Brush brush;
                     Pen pen = new Pen(Color.Black, 1);
                     switch (part.TypeID)
                     {
                         case 0: brush = brushes[0]; break;
                         case 1: brush = brushes[1]; break;
                         case 2: brush = brushes[2]; break;
                         case 4: brush = brushes[3]; break;
                         case 3: brush = brushes[4]; break;
                         case 5: brush = brushes[5]; break;
                         case 6: brush = brushes[6]; break;
                         //case 7: brush = brushes[7]; break;
                         default: brush = null; break;
                     }
                     foreach (var shape in part.Shapes)
                     {
                         for (int i = 0; i < shape.Points.Length; i++)
                         {
                             double x = (shape.Points[i].X + deviationX) * rate;
                             double y = (Height - shape.Points[i].Y - deviationY) * rate;
                             shape.Points[i].X = (float)x;
                             shape.Points[i].Y = (float)y;
                         }
                         if (brush != null)
                             g.FillPolygon(brush, shape.Points);
                         if (part.TypeID != 0 && part.TypeID != 1)
                             g.DrawPolygon(pen, shape.Points);
                     }
                 }
                 string result = FileInfoUtil.ImgToBase64String(bit);
                 g.Dispose();
                 bit.Dispose();
                 return result;
             });
        }

        /// <summary>
        /// 部件颜色设置
        /// </summary>
        private readonly Brush[] brushes = new Brush[8]
        {
            Brushes.LightGray,//梁
            Brushes.LightGray,//地板
            Brushes.Black,//墙
            Brushes.Orange,//门
            Brushes.Black,//柱子
            Brushes.SkyBlue,//窗
            Brushes.LightGreen,//隔墙
            Brushes.Transparent//房间
        };

        /// <summary>
        /// 部件颜色设置
        /// </summary>
        private readonly Color[] pens = new Color[8]
        {
            Color.LightGray,//梁
            Color.LightGray,//地板
            Color.Black,//墙
            Color.Orange,//门
            Color.Black,//柱子
            Color.SkyBlue,//窗
            Color.LightGreen,//隔墙
            Color.Transparent//房间
        };
    }

    /// <summary>
    /// LayoutPartStruct
    /// </summary>
    public class LayoutPartStruct
    {
        public List<PointSet> Shapes { get; set; }
        public string ID { get; set; }
        public int TypeID { get; set; }
        public string TypeName { get; set; }

        public LayoutPartStruct()
        {
            Shapes = new List<PointSet>();
        }
    }

    /// <summary>
    /// PointSet
    /// </summary>
    public class PointSet
    {
        public PointF[] Points { get; set; }

        public PointSet(int count)
        {
            Points = new PointF[count];
        }
    }

    /// <summary>
    /// HouseMapPoint
    /// </summary>
    public class HouseMapPoint
    {
        public double x { get; set; }
        public double y { get; set; }
        public string offsetX { get; set; }
        public string offsetY { get; set; }
    }

    public class ElCascaderTreeDataDto
    {
        public string value { get; set; }
        public string label { get; set; }
        public ElCascaderTreeDataDto[] children { get; set; }
        public bool disabled { get; set; }
    }

    public partial class MsHouseMapDto
    {
        /// <summary>
        /// 项目Id
        /// </summary>
        public Guid HouseMapId { get; set; }

        /// <summary>
        /// 户型图名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 户型图url
        /// </summary>
        public string Image_Base { get; set; }

        /// <summary>
        /// 项目Id
        /// </summary>
        public Guid ProjectId { get; set; }

        /// <summary>
        /// 标准层类型：0：非标准层，1：标准层
        /// </summary>
        public int MapType { get; set; }

        /// <summary>
        /// 户型列表
        /// </summary>
        public KeyAndName[] HouseTypes { get; set; }

        /// <summary>
        /// 测量站点
        /// </summary>
        public List<MeasurePoints> MeasurePoints { get; set; }

        /// <summary>
        /// 户型
        /// </summary>
        public string HouseType { get; internal set; }

        /// <summary>
        /// 户型图面积
        /// </summary>
        public double MapArea { get; set; }

        /// <summary>
        /// 数据类型：0（实测户型图）、1（CAD数据）、2 （FMS模式数据）
        /// </summary>
        public int DataType { get; set; }

        /// <summary>
        /// 是否已减去圆圈半径
        /// </summary>
        public bool HasMinus { get; set; }

        /// <summary>
        /// 此户型图是否已发布
        /// </summary>
        public bool HasProjectPublished { get; set; }
    }

    public class HouseMapCondition
    {
        /// <summary>
        /// 站点类型Id
        /// </summary>
        public Guid MsPointTypeId { get; set; }

        public Guid? ProjectGuid { get; set; }
    }
}